//============================================================================================
/**
 * @file	result_data.c
 * @brief	結果データ
 * @author	Nozomu Saito
 */
//============================================================================================

#include "result_data.h"
#include "application/pokethlon_frame.h"	//for PKTHLN_EVT_MAX

#include "system/msgdata_util.h"
#include "strbuf_family.h"

#include "msgdata/msg.naix"

#define DATA_NUM_DEFAULT	(4)

typedef  struct NODE_tag NODE;

typedef struct NODE_tag
{
	NODE *Prev;
	NODE *Next;
	RESULT_DATA *Data;
}NODE;

typedef struct RESULT_tag
{
	int DataNum;
	BOOL IconValid;
	int EntryPoint;
	SORT_TYPE SortType;
	BOOL AddFlg;
	int TotalScore[ENTRY_MEMBER_NUM_MAX];
	RESULT_DATA Result[ENTRY_MEMBER_NUM_MAX*ENTRY_MAX];
	RESULT_DATA *ResultPtr[ENTRY_MEMBER_NUM_MAX*ENTRY_MAX];
	int Score[PKTHLN_EVT_MAX][ENTRY_MEMBER_NUM_MAX];
}RESULT;

//----------------------------------------------------------------------------
/**
 *	@brief  アロケーション
 *
 *	@param	inHeapID	ヒープID
 *
 *	@return ptr		リザルトポインタ
 */
//-----------------------------------------------------------------------------
RSLT_PTR RSLT_Alloc(const int inHeapID)
{
	RSLT_PTR ptr;
	int i;
	ptr = sys_AllocMemory( inHeapID, sizeof(RESULT) );
	//メモリクリア
	MI_CpuClear8( ptr, sizeof(RESULT));

	for(i=0;i<ENTRY_MEMBER_NUM_MAX*ENTRY_MAX;i++){
		//STRBUFのアロケート
		ptr->Result[i].Record = STRBUF_Create( RECORD_STR_LEN, inHeapID );
		ptr->Result[i].NickName = STRBUF_Create( MONS_NAME_SIZE+EOM_SIZE, inHeapID );
	}
	return  ptr;
}

//----------------------------------------------------------------------------
/**
 *	@brief  解放
 *
 *	@param	ptr		リザルトポインタ
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
void RSLT_Free(RSLT_PTR ptr)
{
	int i;
	for(i=0;i<ENTRY_MEMBER_NUM_MAX*ENTRY_MAX;i++){
		//STRBUFの解放
		STRBUF_Delete( ptr->Result[i].Record );
		STRBUF_Delete( ptr->Result[i].NickName );
	}
	sys_FreeMemoryEz(ptr);
}

//----------------------------------------------------------------------------
/**
 *	@brief	エントリー
 *
 *	@param	ptr				リザルトポインタ
 *
 *	@return	RESULT_DATA *	リザルトデータポインタ
 */
//-----------------------------------------------------------------------------
RESULT_DATA *RSLT_GetEntryResultData(RSLT_PTR ptr)
{
	GF_ASSERT(ptr->EntryPoint < ENTRY_MEMBER_NUM_MAX);
	GF_ASSERT(ptr->EntryPoint < ptr->DataNum);

	return &ptr->Result[ ptr->EntryPoint++ ];
}

//----------------------------------------------------------------------------
/**
 *	@brief	リザルトデータ取得
 *
 *	@param	ptr				リザルトポインタ
 *	@param	inIdx			インデックス
 *
 *	@return	RESULT_DATA *	リザルトデータポインタ
 */
//-----------------------------------------------------------------------------
RESULT_DATA *RSLT_GetResultData(RSLT_PTR ptr, const u8 inIdx)
{
	GF_ASSERT(inIdx < ENTRY_MEMBER_NUM_MAX);
	GF_ASSERT(inIdx < ptr->DataNum);

	return &ptr->Result[ inIdx ];
}

//----------------------------------------------------------------------------
/**
 *	@brief			エントリーのリセット
 *
 *	@param	ptr		リザルトポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
void RSLT_ResetEntryResultData(RSLT_PTR ptr)
{
	int i;
	ptr->DataNum = 0;
	ptr->IconValid = FALSE;
	ptr->EntryPoint = 0;
	ptr->SortType = SORT_TYPE_NONE;
	//再加算防止フラグをおとす
	ptr->AddFlg = FALSE;
	for(i=0;i<ENTRY_MEMBER_NUM_MAX*ENTRY_MAX;i++){
		ptr->ResultPtr[i] = NULL;
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	ソート
 *
 *	@param	ptr			リザルトポインタ
 *	@param	inCode		ソートコード
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
void RSLT_Sort(RSLT_PTR ptr, const SORT_CODE inCode)
{
	int i, j;

	int sort_type;

	NODE node[1+ENTRY_MEMBER_NUM_MAX*ENTRY_MAX];

	//準備
	node[0].Prev = &node[1];
	node[0].Next = &node[1];
	node[0].Data = NULL;

	switch(inCode){
	case SORT_SCORE:
		sort_type = SORT_TYPE_LARGE;
		break;
	case SORT_REC_LARGE:
		sort_type = SORT_TYPE_LARGE;
		break;
	case SORT_REC_SMALL:
		sort_type = SORT_TYPE_SMALL;
		break;
	default:
		GF_ASSERT(0);
	}

	ptr->SortType = sort_type;

	for(i=0;i<ptr->DataNum;i++){
		NODE *now;
		NODE *target;
		//ノード取得
		now = &node[i+1];
		//値セット
		now->Data = &ptr->Result[i];
		now->Next = NULL;
		now->Prev = NULL;

		target = &node[0];
		for(j=0;j<i;j++){
			target = target->Next;
			if (sort_type == SORT_TYPE_LARGE){		//昇順
				//挿入
				if (target->Data->RecordOrg < now->Data->RecordOrg){	//値が大きい
					//リストの前に追加
					target->Prev->Next = now;
					now->Prev = target->Prev;
					now->Next = target;
					target->Prev = now;
					break;
				}else if( (target->Data->RecordOrg == now->Data->RecordOrg)&&
						(target->Data->NetID > now->Data->NetID) ){	//値が同じでも、インデックスが若い
					//リストの前に追加
					target->Prev->Next = now;
					now->Prev = target->Prev;
					now->Next = target;
					target->Prev = now;
				}
			}else{									//降順
				//挿入
				if (target->Data->RecordOrg > now->Data->RecordOrg){	//値が小さい
					//リストの前に追加
					target->Prev->Next = now;
					now->Prev = target->Prev;
					now->Next = target;
					target->Prev = now;
					break;
				}else if( (target->Data->RecordOrg == now->Data->RecordOrg)&&
						(target->Data->NetID > now->Data->NetID) ){	//値が同じでも、インデックスが若い
					//リストの前に追加
					target->Prev->Next = now;
					now->Prev = target->Prev;
					now->Next = target;
					target->Prev = now;
				}
			}
		}
		if (j==i){
			//リスト最後に追加
			target->Next = now;
			now->Prev = target;
		}
	}

	//ソート終わったら、配列に格納しなおす
	{
		NODE *now;
		int record;
		int rank;
		u8 check;
		now = &node[0];
		record = 0xffffffff;
		rank = -1;
		check = 0;
		for(i=0;i<ptr->DataNum;i++){
			now = now->Next;
			ptr->ResultPtr[i] = now->Data;
			//順位セット
			if (record!=now->Data->RecordOrg){
				record = now->Data->RecordOrg;
				if (check){
					rank = i;
					check = 0;
				}else{
					rank++;
				}
			}else{
				check = 1;
			}
			ptr->ResultPtr[i]->Rank = rank;
		}
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	リザルトデータ取得
 *
 *	@param	ptr			リザルトポインタ
 *	@param	inIndex		インデックス
 *
 *	@return	RESULT_DATA *	リザルトデータポインタ
 */
//-----------------------------------------------------------------------------
RESULT_DATA *RSLT_GetResultDataPtr(RSLT_PTR ptr, const u8 inIndex)
{
	GF_ASSERT(inIndex < ENTRY_MEMBER_NUM_MAX);
	GF_ASSERT(inIndex < ptr->DataNum);
	return  ptr->ResultPtr[inIndex];
}

//----------------------------------------------------------------------------
/**
 *	@brief	セットアップ
 *
 *	@param	ptr				リザルトポインタ
 *	@param	inDataNum		データ件数
 *	@param	inIconValid		アイコン表示有無
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
void RSLT_SetupEx(RSLT_PTR ptr, const int inDataNum, const BOOL inIconValid)
{
	RSLT_ResetEntryResultData(ptr);

	ptr->DataNum = inDataNum;
	ptr->IconValid = inIconValid;
}

//----------------------------------------------------------------------------
/**
 *	@brief	セットアップ
 *
 *	@param	ptr				リザルトポインタ
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
void RSLT_Setup(RSLT_PTR ptr)
{
	RSLT_ResetEntryResultData(ptr);

	ptr->DataNum = DATA_NUM_DEFAULT;
	ptr->IconValid = FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	データ件数取得
 *
 *	@param	ptr		リザルトポインタ
 *
 *	@return	int		データ件数
 */
//-----------------------------------------------------------------------------
int RSLT_GetDataNum(RSLT_PTR ptr)
{
	return ptr->DataNum;
}

//----------------------------------------------------------------------------
/**
 *	@brief	アイコン有無取得
 *
 *	@param	ptr		リザルトポインタ
 *
 *	@return	BOOL		TRUE：アイコンあり　FALSE：アイコンなし
 */
//-----------------------------------------------------------------------------
BOOL RSLT_IsValidPokeIcon(RSLT_PTR ptr)
{
	return ptr->IconValid;
}

//----------------------------------------------------------------------------
/**
 *	@brief	合計得点に加算
 *
 *	@param	ptr		リザルトポインタ
 *
 *	@return　none
 */
//-----------------------------------------------------------------------------
void RSLT_AddTotalScore(RSLT_PTR ptr)
{
	int i;
	int idx;

	//再加算しようとしている
	GF_ASSERT( !ptr->AddFlg );
	if(ptr->AddFlg){
		return;
	}

	//登録件数分ループ
	for(i=0;i<ptr->DataNum;i++){
		idx = ptr->ResultPtr[i]->NetID;
		ptr->TotalScore[idx] += ptr->ResultPtr[i]->Score;
	}

	//再加算防止フラグを立てる
	ptr->AddFlg = TRUE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	合計点数取得
 *
 *	@param	ptr			リザルトポインタ
 *	@param	inNetID		ネットID
 *
 *	@return int 		合計得点
 */
//-----------------------------------------------------------------------------
int RSLT_GetTotalScore(RSLT_PTR ptr, const int inNetID)
{
	return ptr->TotalScore[inNetID];
}

//----------------------------------------------------------------------------
/**
 *	@brief	競技内得点セット
 *
 *	@param	ptr		リザルトポインタ
 *	@param	inEvtIdx	競技インデックス
 *
 *	@return　none
 */
//-----------------------------------------------------------------------------
void RSLT_SetEvtScore(RSLT_PTR ptr, const int inEvtIdx)
{
	int i;
	int idx;
	int event;

	int score[ENTRY_MEMBER_NUM_MAX] = {0,0,0,0};


	GF_ASSERT(inEvtIdx < PKTHLN_EVT_MAX);

	//登録件数分ループ
	for(i=0;i<ptr->DataNum;i++){
		idx = ptr->ResultPtr[i]->NetID;
		score[idx] += ptr->ResultPtr[i]->Score;
	}

	for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		ptr->Score[inEvtIdx][i] = score[i];
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	競技点数取得
 *
 *	@param	ptr			リザルトポインタ
 *	@param	inEvtIdx	競技インデックス
 *	@param	inNetID		ネットID
 *
 *	@return int 		得点
 */
//-----------------------------------------------------------------------------
int RSLT_GetEvtScore(RSLT_PTR ptr, const int inEvtIdx, const int inNetID)
{
	GF_ASSERT(inEvtIdx < PKTHLN_EVT_MAX);
	return ptr->Score[inEvtIdx][inNetID];
}

#if 0
//----------------------------------------------------------------------------
/**
 *	@brief　競技結果セット
 *
 *  @param  work			ポケスロンポインタ
 *	@param	ptr				リザルトポインタ
 *	@param	inNetID			ネットID
 *	@param	inEntryNo		ポケモンエントリ番号 0〜2
 *	@param	inRecordOrg		競技成績
 *	@param	inReg			ワードセットレジスタ
 *	@param	inDigit			桁
 *	@param	inMsgId			メッセージＩＤ
 *
 *	@return int 		得点
 */
//-----------------------------------------------------------------------------
void RSLT_SetResultEx(	PKTHLN_PTR work, RSLT_PTR ptr,
						const int inNetID, const u8 inEntryNo,
						const int inRecordOrg,
						const u8 inReg, const u8 inDigit, const int inMsgID )
{
	int heap;
	RESULT_DATA * result;

	MSGDATA_MANAGER *msgman;

	heap = PTFrame_GetHeapID(work);

	msgman = MSGMAN_Create(MSGMAN_TYPE_DIRECT, ARC_MSG,
					NARC_msg_pokethlon_dat, heap);

	result = RSLT_GetEntryResultData(ptr);
	result->NetID = inNetID;
	result->RecordOrg = inRecordOrg;
	if (ptr->IconValid){
		POKETHLON_ENTRY_DATA *entry;
		entry = PTFrame_GetEntryDataPtrByID(work, inNetID);
		result->MonsNo = entry[inEntryNo].MonsNo;
		result->Form = entry[inEntryNo].Form;
		result->PokeIdx = inEntryNo;
		//ニックネーム
		STRBUF_SetStringCode( result->NickName, entry[inEntryNo].NickName );
	}

	{
		//成績加工
		STRBUF *str;
		WORDSET *word;

		int record = result->RecordOrg;

		//アーカイブから展開して表示
		word = WORDSET_Create(heap);
		WORDSET_RegisterNumber(word, inReg, record, inDigit,
		NUMBER_DISPTYPE_SPACE,NUMBER_CODETYPE_DEFAULT);
		str = MSGDAT_UTIL_AllocExpandString(word, msgman, inMsgID, heap);
		WORDSET_Delete(word);
		//コピー
		STRBUF_Copy( result->Record, str );
		STRBUF_Delete(str);
	}
	MSGMAN_Delete( msgman );

}
#endif

//----------------------------------------------------------------------------
/**
 *	@brief　競技結果セット
 *
 *  @param  work			ポケスロンポインタ
 *	@param	ptr				リザルトポインタ
 *	@param	inNetID			ネットID
 *	@param	inRecordOrg		競技成績
 *	@param	inReg			ワードセットレジスタ
 *	@param	inDigit			桁
 *	@param	inMsgID			メッセージＩＤ
 *
 *	@return int 		得点
 */
//-----------------------------------------------------------------------------
void RSLT_SetResult(PKTHLN_PTR work, RSLT_PTR ptr,
					const int inNetID, const int inRecordOrg,
					const u8 inReg, const u8 inDigit, const int inMsgID )
{
	int heap;
	RESULT_DATA * result;

	MSGDATA_MANAGER *msgman;

	heap = PTFrame_GetHeapID(work);

	msgman = MSGMAN_Create(MSGMAN_TYPE_DIRECT, ARC_MSG,
					NARC_msg_pokethlon_dat, heap);

	result = RSLT_GetEntryResultData(ptr);
	result->NetID = inNetID;
	result->RecordOrg = inRecordOrg;

	{
		//成績加工
		STRBUF *str;
		WORDSET *word;

		int record = result->RecordOrg;

		//アーカイブから展開して表示
		word = WORDSET_Create(heap);
		WORDSET_RegisterNumber(word, inReg, record, inDigit,
		NUMBER_DISPTYPE_SPACE,NUMBER_CODETYPE_DEFAULT);
		str = MSGDAT_UTIL_AllocExpandString(word, msgman, inMsgID, heap);
		WORDSET_Delete(word);
		//コピー
		STRBUF_Copy( result->Record, str );
		STRBUF_Delete(str);
	}
	MSGMAN_Delete( msgman );

}

//----------------------------------------------------------------------------
/**
 *	@brief　競技結果セット
 *
 *  @param  work			ポケスロンポインタ
 *	@param	ptr				リザルトポインタ
 *	@param	inNetID			ネットID
 *	@param	inRecordOrg		競技成績
 *	@param	inRec1			レコード
 *  @param	inRec2			レコード
 *	@param	inReg1			ワードセットレジスタ
 *	@param	inReg2			ワードセットレジスタ
 *	@param	inDigit1		桁
 *	@param	inDigit2		桁
 *	@param	inMsgID			メッセージＩＤ
 *
 *	@return int 		得点
 */
//-----------------------------------------------------------------------------
void RSLT_SetResult2(PKTHLN_PTR work, RSLT_PTR ptr, const int inNetID, const u16 inRecordOrg,
						const int inRec1, const int inRec2,
						const u8 inReg1, const u8 inReg2,
						const u8 inDigit1, const u8 inDigit2, const int inMsgID )
{
	int heap;
	RESULT_DATA * result;

	MSGDATA_MANAGER *msgman;

	heap = PTFrame_GetHeapID(work);

	msgman = MSGMAN_Create(MSGMAN_TYPE_DIRECT, ARC_MSG,
					NARC_msg_pokethlon_dat, heap);

	result = RSLT_GetEntryResultData(ptr);
	result->NetID = inNetID;
	result->RecordOrg = inRecordOrg;

	{
		//成績加工
		STRBUF *str;
		WORDSET *word;

		int rec1 = inRec1;
		int rec2 = inRec2;

		//アーカイブから展開して表示
		word = WORDSET_Create(heap);
		WORDSET_RegisterNumber(word, inReg1, rec1, inDigit1,
				NUMBER_DISPTYPE_SPACE,NUMBER_CODETYPE_DEFAULT);
		WORDSET_RegisterNumber(word, inReg2, rec2, inDigit2,
				NUMBER_DISPTYPE_SPACE,NUMBER_CODETYPE_DEFAULT);
		str = MSGDAT_UTIL_AllocExpandString(word, msgman, inMsgID, heap);
		WORDSET_Delete(word);
		//コピー
		STRBUF_Copy( result->Record, str );
		STRBUF_Delete(str);
	}
	MSGMAN_Delete( msgman );
}